home *** CD-ROM | disk | FTP | other *** search
/ PC Plus SuperCD (UK) 1997 February / PC Plus Super CD (Issue 124) (PCP124-2-97) (February 1997).iso / handson / delphi / outline3 / outl3.pas < prev    next >
Encoding:
Pascal/Delphi Source File  |  1996-10-14  |  9.9 KB  |  302 lines

  1. unit Outl3;
  2. { PC PLUS sample Outliner program.
  3. Author: Huw Collingbourne
  4.  
  5. Demonstrates how to use Delphi's outline object to create a collapsible
  6. outliner. Lets you add and delete items and save/load outlines to/from disk.
  7.  
  8. Be aware that Delphi 1's outline component is a bit buggy. I've tried
  9. to work around the main problems (particularly the ChangeByLevel method).
  10. As far as I can tell, Delphi 2's outline component works OK.
  11.  
  12. Features added in this version:
  13. 1) When an item is clicked, its text appears in the edit box.
  14. 2) A change button lets you change an item's text to the contents of edit box.
  15. 3) When an outline is loaded, it is shown fully expanded.
  16. 4) There are buttons to indent and outdent items.
  17. 5) You can re-order items by dragging and dropping them.
  18.  
  19. Ideas for further improvements:
  20. * Pop up a Yes/No message box to let the user back out of a delete operation
  21.   when child items exist beneath the selected item.
  22. * Add extra buttons to do a FullExpand or FullCollapse of the outline.
  23.  
  24. Note: This is program is purely for demonstration purposes.
  25. There is a minimum of error checking and error recovery. It is
  26. not guaranteed to function flawlessly!!!
  27. }
  28.  
  29. interface
  30.  
  31. uses
  32.   SysUtils, WinTypes, WinProcs, Messages, Classes, Graphics, Controls,
  33.   Forms, Dialogs, Grids, Outline, ExtCtrls, StdCtrls, Menus;
  34.  
  35. type
  36.   TForm1 = class(TForm)
  37.     Panel1: TPanel;
  38.     Outline1: TOutline;
  39.     ItemTextEd: TEdit;
  40.     AddItemBtn: TButton;
  41.     DelBtn: TButton;
  42.     OpenDialog1: TOpenDialog;
  43.     SaveDialog1: TSaveDialog;
  44.     MainMenu1: TMainMenu;
  45.     FileMenu: TMenuItem;
  46.     OpenMenuItem: TMenuItem;
  47.     NewMenuItem: TMenuItem;
  48.     SaveMenuItem: TMenuItem;
  49.     SaveAsMenuItem: TMenuItem;
  50.     ExitMenuItem: TMenuItem;
  51.     ChangeBtn: TButton;
  52.     OutBtn: TButton;
  53.     InBtn: TButton;
  54.     procedure AddItemBtnClick(Sender: TObject);
  55.     procedure DelBtnClick(Sender: TObject);
  56.     procedure Outline1Click(Sender: TObject);
  57.     procedure ExitMenuItemClick(Sender: TObject);
  58.     procedure NewMenuItemClick(Sender: TObject);
  59.     procedure SaveMenuItemClick(Sender: TObject);
  60.     procedure SaveAsMenuItemClick(Sender: TObject);
  61.     procedure OpenMenuItemClick(Sender: TObject);
  62.     procedure ChangeBtnClick(Sender: TObject);
  63.     procedure OutBtnClick(Sender: TObject);
  64.     procedure InBtnClick(Sender: TObject);
  65.     procedure Outline1DragOver(Sender, Source: TObject; X, Y: Integer;
  66.       State: TDragState; var Accept: Boolean);
  67.     procedure Outline1DragDrop(Sender, Source: TObject; X, Y: Integer);
  68.     procedure Outline1MouseDown(Sender: TObject; Button: TMouseButton;
  69.       Shift: TShiftState; X, Y: Integer);
  70.     procedure Outline1MouseMove(Sender: TObject; Shift: TShiftState; X,
  71.       Y: Integer);
  72.   private
  73.     { Private declarations }
  74.   public
  75.     { Public declarations }
  76.   end;
  77.  
  78. var
  79.   Form1: TForm1;
  80.   DragSourceItem :Integer; { save the row number of source drag&drop item }
  81.  
  82. implementation
  83.  
  84. {$R *.DFM}
  85.  
  86. function ConfirmFileSave(FileName : string) : boolean;
  87. begin
  88.     if MessageDlg(FileName + ' already exists. Save anyway?',
  89.                         mtConfirmation, mbYesNoCancel, 0)
  90.                         = mrYes then
  91.       ConfirmFileSave := true
  92.     else
  93.       ConfirmFileSave := false;
  94. end;
  95.  
  96. procedure TForm1.AddItemBtnClick(Sender: TObject);
  97. { Adds text from ItemTextEd text box to the outline as a 'child' item -
  98.   that is, an item indented one level }
  99. var
  100.    ItemText : string;
  101.    NewIndex : LongInt; { Index of child item }
  102. begin
  103.   ItemText := ItemTextEd.Text;
  104.   NewIndex := 0;
  105.   If ItemText = '' then
  106.       MessageDlg('You must enter text for this item!', mtInformation,
  107.       [mbOk], 0)
  108.   else
  109.   If Outline1.Lines.Count = 0 then
  110.      Outline1.Add(0,ItemText)
  111.   else
  112.   begin
  113.       NewIndex := Outline1.AddChild(Outline1.SelectedItem, ItemText );
  114.      { expand selected item so you can see your new subitem }
  115.      Outline1[Outline1.SelectedItem].FullExpand; 
  116.      { move highlight to new subitem }
  117.      Outline1.SelectedItem := NewIndex;
  118.   end;
  119.      { give focus to text edit box }
  120.   ActiveControl:= ItemTextEd;
  121.     { select text in edit box, ready for deletion if necessary }
  122.   ItemTextEd.SelectAll;
  123.  end;
  124.  
  125. procedure TForm1.DelBtnClick(Sender: TObject);
  126. { Deletes the current item and all child items beneath it.
  127.   You may want to add a Yes/No message box to let the user
  128.   confirm this deletion }
  129. begin
  130.       { if no item is selected, don't do anything }
  131.    If Outline1.SelectedItem > 0 then
  132.       Outline1.Delete(Outline1.SelectedItem);
  133.      { give focus to text edit box }
  134.   ActiveControl:= ItemTextEd;
  135.   ItemTextEd.Text := '';
  136. end;
  137.  
  138. procedure TForm1.Outline1Click(Sender: TObject);
  139. { Put text of selected item into edit box (handy if you want to change text) }
  140. { DELPHI 1 USERS NOTE: Because of a bug in the Delphi 1 Outline component,   }
  141. { a click event is generated when items are moved. However, the outline is   }
  142. { only reindexed after this event. This means, this method will cause an     }
  143. { 'index out of bounds' exception. Delphi 1 users may, therefore, want to    }
  144. { bracket out all the code between 'begin' and 'end'. This will not alter    }
  145. { the outliner's functionality to any significant degree.                    }
  146. begin
  147. If Outline1.SelectedItem > 0 then
  148.      ItemTextEd.Text := Outline1.Items[Outline1.SelectedItem].Text;
  149.   ActiveControl:= ItemTextEd;
  150. end;
  151.  
  152. procedure TForm1.ExitMenuItemClick(Sender: TObject);
  153. begin
  154.   Close;
  155. end;
  156.  
  157. procedure TForm1.NewMenuItemClick(Sender: TObject);
  158. begin
  159.   Outline1.Clear;
  160.   OpenDialog1.FileName := '*.otl';
  161. end;
  162.  
  163. { Some basic File Saving and Opening procedures }
  164. procedure TForm1.SaveAsMenuItemClick(Sender: TObject);
  165. var
  166.    SaveFile : boolean;
  167. begin
  168.    SaveFile := true;
  169.    with SaveDialog1 do
  170.     if Execute then
  171.     begin
  172.       if FileExists(FileName) then
  173.          SaveFile := ConfirmFileSave(FileName);
  174.       If SaveFile then
  175.       begin
  176.          Outline1.Lines.SaveToFile(Filename);
  177.          OpenDialog1.Filename := Filename;
  178.       end;
  179.     end;
  180. end;
  181.  
  182.  
  183. procedure TForm1.SaveMenuItemClick(Sender: TObject);
  184. begin
  185.   if ((OpenDialog1.Filename = '') or (OpenDialog1.Filename = '*.otl')) then
  186.     SaveAsMenuItemClick(Sender)
  187.   else
  188.     Outline1.Lines.SaveToFile(OpenDialog1.Filename);
  189. end;
  190.  
  191.  
  192. procedure TForm1.OpenMenuItemClick(Sender: TObject);
  193. begin
  194.   with OpenDialog1 do
  195.     if Execute then
  196.     begin
  197.       if FileExists(FileName) Then
  198.       begin
  199.           Outline1.Lines.LoadFromFile(FileName);
  200.            { if outline isn't empty, show outline expanded }
  201.            If Outline1.SelectedItem > 0 then
  202.               Outline1[Outline1.SelectedItem].FullExpand;
  203.       end
  204.       else
  205.         MessageDlg('Sorry. Can''t load this file. '+ FileName +
  206.                            ' does not exist!',
  207.                         mtInformation, [mbOK], 0);
  208.     end;
  209. end;
  210.  
  211. procedure TForm1.ChangeBtnClick(Sender: TObject);
  212. { Change the text of the item selected in the outline }
  213. begin
  214.   If Outline1.SelectedItem > 0 then
  215.     Outline1.Items[Outline1.SelectedItem].Text := ItemTextEd.Text;
  216. end;
  217.  
  218. procedure TForm1.OutBtnClick(Sender: TObject);
  219. { Move an item out one level. This is used in place of the ChangeByLevel
  220.   method which, in Delphi 1, does not work as documented in the Delphi help
  221.   files and manuals }
  222. begin
  223. If Outline1.SelectedItem > 0 then
  224.   with OutLine1.Items[OutLine1.SelectedItem] do begin
  225.     { Don't do anything if this is the top item }
  226.     if Level > 1 then
  227.       { Move it to become a 'child' of its parent item's parent - i.e.
  228.         move it 'out' one level }
  229.       MoveTo(Parent.Index,oaAdd);
  230.       Outline1[Outline1.SelectedItem].FullExpand;
  231.   end;
  232. end;
  233.  
  234. procedure TForm1.InBtnClick(Sender: TObject);
  235. { Move an item in one level. ChangeLevelBy works OK here. }
  236. begin
  237.   If Outline1.SelectedItem > 0 then
  238.   begin
  239.     with Outline1[Outline1.SelectedItem] do
  240.        { check the item has somewhere to move to! }
  241.       if Parent.GetPrevChild(Index) <> -1 then
  242.         ChangeLevelBy(1);
  243.     Outline1[Outline1.SelectedItem].FullExpand;
  244.   end;
  245. end;
  246.  
  247.  
  248. { DRAG AND DROP }
  249. procedure TForm1.Outline1DragOver(Sender, Source: TObject; X, Y: Integer;
  250.   State: TDragState; var Accept: Boolean);
  251. begin
  252.   { don't do anything unless there is an item selected }
  253.   If Outline1.SelectedItem > 0 then
  254.     begin
  255.        { it will accept item if dropped  }
  256.       Accept := True;
  257.        { higlight the item under pointer }
  258.       Outline1.SelectedItem := Outline1.GetItem(X,Y);
  259.     end;
  260. end;
  261.  
  262. procedure TForm1.Outline1DragDrop(Sender, Source: TObject; X, Y: Integer);
  263. begin
  264.          { move Source item (index specified by DragSourceItem) to become
  265.            a child of the currently selected item }
  266.  if (Source is TOutline) and ((DragSourceItem > 0)) then
  267.     begin
  268.         Outline1.Items[DragSourceItem].MoveTo(Outline1.SelectedItem,oaAddChild);
  269.         { expand branch so we can see item that's been moved }
  270.         Outline1[Outline1.SelectedItem].FullExpand;
  271.     end;
  272. end;
  273.  
  274.  
  275.  
  276. procedure TForm1.Outline1MouseDown(Sender: TObject; Button: TMouseButton;
  277.   Shift: TShiftState; X, Y: Integer);
  278. { This saves the originally selected item index in the variable, DragSourceItem.
  279.   This is necessary since the DragOver procedure continually updates the
  280.   SelectedItem in order to place a highlight over each item beneath the mouse
  281.   pointer. Without this variable as a place-marker, we would lose the index
  282.   of the originally selected item. }
  283. begin
  284.   DragSourceItem := Outline1.GetItem(X,Y);
  285. end;
  286.  
  287. procedure TForm1.Outline1MouseMove(Sender: TObject; Shift: TShiftState; X,
  288.   Y: Integer);
  289. begin
  290.    If Outline1.SelectedItem > 0 then
  291.    begin
  292.         { only do anything if the left mouse button is pressed }
  293.     if (ssLeft in Shift) then
  294.         {The false parameter in BeginDrag() lets the mouse move
  295.          5 pixels before the mouse drag-drop pointer appears. }
  296.         Outline1.BeginDrag(false);
  297.    end
  298.    else Outline1.EndDrag(false);
  299. end;
  300.  
  301. end.
  302.